package org.fuys.coder.domain.redemption.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.fuys.coder.common.util.DateUtil;
import org.fuys.coder.domain.act.lottery.model.vo.award.AwardTypeVO;
import org.fuys.coder.domain.act.support.model.req.ActRedemptionReq;
import org.fuys.coder.domain.mailbox.model.req.MailReq;
import org.fuys.coder.domain.mailbox.model.vo.MailTypeVO;
import org.fuys.coder.domain.mailbox.model.vo.MailVO;
import org.fuys.coder.domain.mailbox.service.IMailBoxService;
import org.fuys.coder.domain.redemption.model.req.RedemptionReq;
import org.fuys.coder.domain.redemption.model.vo.RedemptionResult;
import org.fuys.coder.domain.redemption.service.IRedemptionService;
import org.fuys.coder.domain.redemption.service.policy.AwardRedemptionStrategy;
import org.fuys.coder.infrastructure.dao.AwardMapper;
import org.fuys.coder.infrastructure.dao.AwardRedemptionMapper;
import org.fuys.coder.infrastructure.model.po.AwardRedemption;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @projectName: fuys-low-coder
 * @package: org.fuys.coder.domain.redemption.service.impl
 * @className: RedemptionServiceImpl
 * @author: WangJing
 * @description: 兑换服务实现类
 * @date: 2024/8/28 9:25
 * @version: 1.0
 */
@Service
public class RedemptionServiceImpl implements IRedemptionService {

    private final Map<String, AwardRedemptionStrategy> strategyMap;

    private final ExecutorService threadPoolExecutor;

    @Resource
    private AwardMapper awardMapper;

    @Resource
    private IMailBoxService mailBoxService;

    @Resource
    private AwardRedemptionMapper awardRedemptionMapper;

    @Autowired
    public RedemptionServiceImpl(ListableBeanFactory beanFactory){
        strategyMap = beanFactory.getBeansOfType(AwardRedemptionStrategy.class);
        threadPoolExecutor= Executors.newFixedThreadPool(2);
    }


    @Override
    public RedemptionResult actRedemptionAward(ActRedemptionReq req) {
        //查询出奖品信息以方便使用
        final AwardRedemption awardRedemption = awardRedemptionMapper.selectOne(new LambdaQueryWrapper<AwardRedemption>()
                .select(AwardRedemption::getId,AwardRedemption::getUserId, AwardRedemption::getRedemptionCode, AwardRedemption::getExpiredTime,
                        AwardRedemption::getAwardId, AwardRedemption::getAwardType).eq(AwardRedemption::getUserId, req.getUserId())
                .eq(AwardRedemption::getRedemptionCode, req.getRedemptionCode()));
        if(awardRedemption==null){
            return RedemptionResult.abnormal("兑换码不正确");
        }
        final String strategyName = AwardTypeVO.getTypeInfo(awardRedemption.getAwardType()).getRight();
        if(strategyMap.containsKey(strategyName)){
            //首先对奖品内容进行基本核对 如果出现不对的情况 可拒绝并销毁此纪录 因为这些逻辑是通用的 可以在这里进行
            if(awardRedemption.getExpiredTime().before(new Date())){
                awardRedemptionMapper.deleteById(awardRedemption.getAwardId());
                return RedemptionResult.abnormal("兑换码已过期");
            }
            //进行线程池控制 对于任何异常 都直接将其存入收件箱即可
            final AwardRedemptionStrategy awardRedemptionStrategy = strategyMap.get(strategyName);
            Callable<RedemptionResult> task = ()->{
                RedemptionReq redemptionReq=new RedemptionReq();
                redemptionReq.setUserId(req.getUserId());
                redemptionReq.setAwardCode(req.getRedemptionCode());
                return awardRedemptionStrategy.doRedemption(redemptionReq,awardRedemption);
            };
            CompletableFuture<RedemptionResult> redemptionResult=CompletableFuture.supplyAsync(()->{
                try {
                    return task.call();
                }
                catch (Exception e) {
                    e.printStackTrace();
                    MailReq mailReq=new MailReq();
                    MailVO mailVO=new MailVO();
                    mailVO.setData("兑换失败 如果频繁出现此情况 请反馈客服");
                    mailVO.setExpire(DateUtil.addTimeFromCur(1,TimeUnit.DAYS).getTime());
                    mailVO.setType(MailTypeVO.MAIL_TYPE_MESSAGE);
                    mailReq.setToIds(Collections.singletonList(req.getUserId()));
                    mailReq.setMailVO(mailVO);
                    mailBoxService.publishMail(mailReq);
                    return null;
                }
            },threadPoolExecutor);
            redemptionResult.thenApply(result->{
                MailReq mailReq=new MailReq();
                MailVO mailVO=new MailVO();
                result.setMsg("您的兑换已生效");
                mailVO.setData(result);
                mailVO.setExpire(DateUtil.addTimeFromCur(1,TimeUnit.DAYS).getTime());
                mailVO.setType(MailTypeVO.MAIL_TYPE_MESSAGE);
                mailReq.setToIds(Collections.singletonList(req.getUserId()));
                mailReq.setMailVO(mailVO);
                mailBoxService.publishMail(mailReq);
                return result;
            });
            return RedemptionResult.normal("兑换进行中 奖品到账可能存在一定延迟 请耐心等待");
        }
        return null;
    }
}
